#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/types.h>

#include "ch9.h"
#include "functionfs.h"

#define USB_FFS_ADB_PATH  "/dev/usb-ffs/adb/"
#define USB_FFS_ADB_EP(x) USB_FFS_ADB_PATH#x
#define STR_INTERFACE_ "ADB Interface"

#define USB_FFS_ADB_EP0   USB_FFS_ADB_EP(ep0)
#define USB_FFS_ADB_OUT   USB_FFS_ADB_EP(ep1)
#define USB_FFS_ADB_IN    USB_FFS_ADB_EP(ep2)

#define ADB_CLASS              0xff
#define ADB_SUBCLASS           0x42
#define ADB_PROTOCOL           0x1

#define MAX_PACKET_SIZE_FS	64
#define MAX_PACKET_SIZE_HS	512
#define MAX_PACKET_SIZE_SS	1024

struct usb_handle
{
    // Legacy f_adb
    int fd;

    // FunctionFS
    int control;
    int bulk_out; /* "out" from the host's perspective => source for adbd */
    int bulk_in;  /* "in" from the host's perspective => sink for adbd */
};

struct func_desc {
    struct usb_interface_descriptor intf;
    struct usb_endpoint_descriptor_no_audio source;
    struct usb_endpoint_descriptor_no_audio sink;
} __attribute__((packed));

struct ss_func_desc {
    struct usb_interface_descriptor intf;
    struct usb_endpoint_descriptor_no_audio source;
    struct usb_ss_ep_comp_descriptor source_comp;
    struct usb_endpoint_descriptor_no_audio sink;
    struct usb_ss_ep_comp_descriptor sink_comp;
} __attribute__((packed));

struct desc_v1 {
    struct usb_functionfs_descs_head_v1 {
        __le32 magic;
        __le32 length;
        __le32 fs_count;
        __le32 hs_count;
    } __attribute__((packed)) header;
    struct func_desc fs_descs, hs_descs;
} __attribute__((packed));


struct desc_v2 {
    struct usb_functionfs_descs_head_v2 header;
    // The rest of the structure depends on the flags in the header.
    __le32 fs_count;
    __le32 hs_count;
    __le32 ss_count;
    __le32 os_count;
    struct func_desc fs_descs, hs_descs;
    struct ss_func_desc ss_descs;
    struct usb_os_desc_header os_header;
    struct usb_ext_compat_desc os_desc;
} __attribute__((packed));

static struct func_desc fs_descriptors;
static struct func_desc hs_descriptors;
static struct ss_func_desc ss_descriptors;
static struct usb_os_desc_header os_desc_header;

struct usb_ext_compat_desc os_desc_compat = {
    .bFirstInterfaceNumber = 0,
    .Reserved1 = 1,
    .CompatibleID = {0},
    .SubCompatibleID = {0},
    .Reserved2 = {0},
};

static const struct {
    struct usb_functionfs_strings_head header;
    struct {
        __le16 code;
        const char str1[sizeof(STR_INTERFACE_)];
    } __attribute__((packed)) lang0;
} __attribute__((packed)) strings = {
    .header = {
        .magic = FUNCTIONFS_STRINGS_MAGIC,
        .length = sizeof(strings),
        .str_count = 1,
        .lang_count = 1,
    },
    .lang0 = {
        0x0409, /* en-us */
        STR_INTERFACE_,
    },
};

static void init_fs_descriptors(void)
{
    fs_descriptors.intf.bLength = sizeof(fs_descriptors.intf);
    fs_descriptors.intf.bDescriptorType = USB_DT_INTERFACE;
    fs_descriptors.intf.bInterfaceNumber = 0;
    fs_descriptors.intf.bNumEndpoints = 2;
    fs_descriptors.intf.bInterfaceClass = ADB_CLASS;
    fs_descriptors.intf.bInterfaceSubClass = ADB_SUBCLASS;
    fs_descriptors.intf.bInterfaceProtocol = ADB_PROTOCOL;
    fs_descriptors.intf.iInterface = 1; /* first string from the provided table */

    fs_descriptors.source.bLength = sizeof(fs_descriptors.source);
    fs_descriptors.source.bDescriptorType = USB_DT_ENDPOINT;
    fs_descriptors.source.bEndpointAddress = 1 | USB_DIR_OUT;
    fs_descriptors.source.bmAttributes = USB_ENDPOINT_XFER_BULK;
    fs_descriptors.source.wMaxPacketSize = MAX_PACKET_SIZE_FS;

    fs_descriptors.sink.bLength = sizeof(fs_descriptors.sink);
    fs_descriptors.sink.bDescriptorType = USB_DT_ENDPOINT;
    fs_descriptors.sink.bEndpointAddress = 2 | USB_DIR_IN;
    fs_descriptors.sink.bmAttributes = USB_ENDPOINT_XFER_BULK;
    fs_descriptors.sink.wMaxPacketSize = MAX_PACKET_SIZE_FS;
}

static void init_hs_descriptors(void)
{
    hs_descriptors.intf.bLength = sizeof(hs_descriptors.intf);
    hs_descriptors.intf.bDescriptorType = USB_DT_INTERFACE;
    hs_descriptors.intf.bInterfaceNumber = 0;
    hs_descriptors.intf.bNumEndpoints = 2;
    hs_descriptors.intf.bInterfaceClass = ADB_CLASS;
    hs_descriptors.intf.bInterfaceSubClass = ADB_SUBCLASS;
    hs_descriptors.intf.bInterfaceProtocol = ADB_PROTOCOL;
    hs_descriptors.intf.iInterface = 1; /* first string from the provided table */

    hs_descriptors.source.bLength = sizeof(hs_descriptors.source);
    hs_descriptors.source.bDescriptorType = USB_DT_ENDPOINT;
    hs_descriptors.source.bEndpointAddress = 1 | USB_DIR_OUT;
    hs_descriptors.source.bmAttributes = USB_ENDPOINT_XFER_BULK;
    hs_descriptors.source.wMaxPacketSize = MAX_PACKET_SIZE_HS;

    hs_descriptors.sink.bLength = sizeof(hs_descriptors.sink);
    hs_descriptors.sink.bDescriptorType = USB_DT_ENDPOINT;
    hs_descriptors.sink.bEndpointAddress = 2 | USB_DIR_IN;
    hs_descriptors.sink.bmAttributes = USB_ENDPOINT_XFER_BULK;
    hs_descriptors.sink.wMaxPacketSize = MAX_PACKET_SIZE_HS;
}

static void init_ss_descriptors(void)
{
    ss_descriptors.intf.bLength = sizeof(ss_descriptors.intf);
    ss_descriptors.intf.bDescriptorType = USB_DT_INTERFACE;
    ss_descriptors.intf.bInterfaceNumber = 0;
    ss_descriptors.intf.bNumEndpoints = 2;
    ss_descriptors.intf.bInterfaceClass = ADB_CLASS;
    ss_descriptors.intf.bInterfaceSubClass = ADB_SUBCLASS;
    ss_descriptors.intf.bInterfaceProtocol = ADB_PROTOCOL;
    ss_descriptors.intf.iInterface = 1; /* first string from the provided table */

    ss_descriptors.source.bLength = sizeof(ss_descriptors.source);
    ss_descriptors.source.bDescriptorType = USB_DT_ENDPOINT;
    ss_descriptors.source.bEndpointAddress = 1 | USB_DIR_OUT;
    ss_descriptors.source.bmAttributes = USB_ENDPOINT_XFER_BULK;
    ss_descriptors.source.wMaxPacketSize = MAX_PACKET_SIZE_SS;

    ss_descriptors.source_comp.bLength = sizeof(ss_descriptors.source_comp);
    ss_descriptors.source_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;

    ss_descriptors.sink.bLength = sizeof(ss_descriptors.sink);
    ss_descriptors.sink.bDescriptorType = USB_DT_ENDPOINT;
    ss_descriptors.sink.bEndpointAddress = 2 | USB_DIR_IN;
    ss_descriptors.sink.bmAttributes = USB_ENDPOINT_XFER_BULK;
    ss_descriptors.sink.wMaxPacketSize = MAX_PACKET_SIZE_SS;

    ss_descriptors.sink_comp.bLength = sizeof(ss_descriptors.sink_comp);
    ss_descriptors.sink_comp.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
}

static void init_os_desc_header(void)
{
    os_desc_header.interface = 1;
    os_desc_header.dwLength = sizeof(os_desc_header) + sizeof(os_desc_compat);
    os_desc_header.bcdVersion = 1;
    os_desc_header.wIndex = 4;
    os_desc_header.bCount = 1;
    os_desc_header.Reserved = 0;
}

static void init_structs(void)
{
    init_fs_descriptors();
    init_hs_descriptors();
    init_ss_descriptors();
    init_os_desc_header();
}
void usb_init()
{
    if (access(USB_FFS_ADB_EP0, F_OK) == 0)
        init_structs();
}

int main(int argc,char **argv)
{
    int ret = 0;
    struct usb_handle *h = NULL;
    struct desc_v1 v1_descriptor;
    struct desc_v2 v2_descriptor;

    // 设置设备描述符信息
    usb_init();
    
    h = malloc(sizeof(struct usb_handle));

    // 填从设备描述符信息
    v2_descriptor.header.magic = FUNCTIONFS_DESCRIPTORS_MAGIC_V2;
    v2_descriptor.header.length = sizeof(v2_descriptor);
    v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
                                 FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
    v2_descriptor.fs_count = 3;
    v2_descriptor.hs_count = 3;
    v2_descriptor.ss_count = 5;
    v2_descriptor.os_count = 1;
    v2_descriptor.fs_descs = fs_descriptors;
    v2_descriptor.hs_descs = hs_descriptors;
    v2_descriptor.ss_descs = ss_descriptors;
    v2_descriptor.os_header = os_desc_header;
    v2_descriptor.os_desc = os_desc_compat;

    // 打开EP0节点
    h->control = open(USB_FFS_ADB_EP0, O_RDWR);
    if (h->control < 0) {
        printf("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno);
        goto err;
    }

    // 往EP0节点写入设备描述符
    ret = write(h->control, &v2_descriptor, sizeof(v2_descriptor));
    if (ret < 0 && errno == EINVAL) {
        v1_descriptor.header.magic = FUNCTIONFS_DESCRIPTORS_MAGIC;
        v1_descriptor.header.length = sizeof(v1_descriptor);
        v1_descriptor.header.fs_count = 3;
        v1_descriptor.header.hs_count = 3;
        v1_descriptor.fs_descs = fs_descriptors;
        v1_descriptor.hs_descs = hs_descriptors;
        printf("[ %s: Switching to V1_descriptor format errno=%d ]\n", USB_FFS_ADB_EP0, errno);
        ret = write(h->control, &v1_descriptor, sizeof(v1_descriptor));
    }

    if (ret < 0) {
        printf("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
        goto err;
    }

    // 通过EP0创建EP1和EP2,写端点和读端点
    ret = write(h->control, &strings, sizeof(strings));
    if (ret < 0) {
        printf("[ %s: writing strings failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno);
        goto err;
    }

    // 获取写端点
    h->bulk_out = open(USB_FFS_ADB_OUT, O_RDWR);
    if (h->bulk_out < 0) {
        printf("[ %s: cannot open bulk-out ep: errno=%d ]\n", USB_FFS_ADB_OUT, errno);
        goto err;
    }

    // 获取读端点
    h->bulk_in = open(USB_FFS_ADB_IN, O_RDWR);
    if (h->bulk_in < 0) {
        printf("[ %s: cannot open bulk-in ep: errno=%d ]\n", USB_FFS_ADB_IN, errno);
        goto err;
    }

    // 阻塞不释放,让Linux的UDC处于ready状态
    while(1) {
        sleep(5);
    }

    close(h->control);
    return 0;

err:
    close(h->control);
    return -1;
}